package net.hn.hnms.biz.video.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import lombok.extern.slf4j.Slf4j;
import net.hn.hnms.biz.video.constant.HikVersionConstant;
import net.hn.hnms.biz.video.domain.*;
import net.hn.hnms.biz.video.service.IHikVisionService;
import net.hn.hnms.sys.common.core.utils.DateUtils;
import net.hn.hnms.sys.common.core.utils.StringUtils;
import net.hn.hnms.sys.common.redis.utils.RedisUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author mkq
 * @Date 2022-08-03 17:51
 * @Description
 */
@Service
@Slf4j
public class HikVisionServiceImpl implements IHikVisionService {

    @Resource
    private HikVersionInfo hikVersionInfo;


    @Override
    public JSONArray resources(boolean isReload) {
        JSONArray cameras = RedisUtils.getCacheObject(HikVersionConstant.CACHE_CAMERA + hikVersionInfo.getApiPrefix());
        if (cameras == null || isReload) {
            iniConfig();
            Map<String, String> path = getPath(HikVersionConstant.CAMERAS);
            JSONObject jsonBody = new JSONObject();
            jsonBody.put("pageNo", 1);
            jsonBody.put("pageSize", hikVersionInfo.getPageSize());
            String body = jsonBody.toJSONString();
            JSONObject responseResult = call(path, body);
            if (responseResult != null && "0".equals(responseResult.getString("code"))) {
                cameras = responseResult.getJSONObject("data").getJSONArray("list");
                RedisUtils.setCacheObject(HikVersionConstant.CACHE_CAMERA + hikVersionInfo.getApiPrefix(), cameras);
            }
        }
        return cameras;
    }


    @Override
    public JSONArray onlineInfo(boolean isReload) {
        JSONArray cameras = RedisUtils.getCacheObject(HikVersionConstant.CACHE_ONLINE_CAMERA + hikVersionInfo.getApiPrefix());
        if (cameras == null || isReload) {
            iniConfig();
            Map<String, String> path = getPath(HikVersionConstant.ONLINE_CAMERA);
            JSONObject jsonBody = new JSONObject();
            jsonBody.put("pageNo", 1);
            jsonBody.put("pageSize", hikVersionInfo.getPageSize());
            String body = jsonBody.toJSONString();
            JSONObject responseResult = call(path, body);
            if (responseResult != null && "0".equals(responseResult.getString("code"))) {
                cameras = responseResult.getJSONObject("data").getJSONArray("list");
                RedisUtils.setCacheObject(HikVersionConstant.CACHE_ONLINE_CAMERA + hikVersionInfo.getApiPrefix(), cameras);
            }
        }
        return cameras;
    }

    @Override
    public List<Camera> list() {
        List<Camera> cameras = new ArrayList<>();
        JSONArray resources = resources(false);
        JSONArray onlineInfo = onlineInfo(false);
        JSONArray areas = regions(false);
        if (resources != null && resources.size() > 0) {
            cameras = resources.stream().map(u -> {
                JSONObject item = (JSONObject) u;
                Integer online = 0;
                String collectTime = "";
                String regionName = "";
                String ip = "";
                String cameraOtherName = "";
                String cameraOtherCode = "";
                if (onlineInfo != null && onlineInfo.size() > 0) {
                    JSONObject on = (JSONObject) onlineInfo.stream()
                            .filter(m -> ((JSONObject) m).getString("indexCode").equals(item.getString("cameraIndexCode")))
                            .findFirst().orElse(null);
                    if (on != null) {
                        online = on.getInteger("online");
                        if (on.getString("collectTime") != null) {
                            collectTime = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", DateUtils.dateTime("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", on.getString("collectTime")));
                        }
                        ip = on.getString("ip");
                    }
                }
                if (areas != null && areas.size() > 0) {
                    JSONObject area = (JSONObject) areas.stream()
                            .filter(m -> ((JSONObject) m).getString("indexCode").equals(item.getString("regionIndexCode")))
                            .findFirst().orElse(null);
                    if (area != null) {
                        regionName = area.getString("name");
                    }
                }
                return new Camera()
                        .setRegionName(regionName)
                        .setCameraIndexCode(item.getString("cameraIndexCode"))
                        .setCameraName(item.getString("cameraName"))
                        .setCameraType(item.getInteger("cameraType"))
                        .setCameraTypeName(item.getString("cameraTypeName"))
                        .setOnline(online)
                        .setCollectTime(collectTime);
            }).collect(Collectors.toList());
        }
        return cameras;
    }

    @Override
    public String getStreamUrl(CameraStream cameraStream) {
        iniConfig();
        Map<String, String> path = getPath(HikVersionConstant.PREVIEWURLS);
        String body = JSONObject.toJSONString(cameraStream);
        JSONObject responseResult = call(path, body);
        String url = "";
        if (responseResult != null) {
            url = responseResult.getJSONObject("data").getString("url");
        }
        return url;
    }

    @Override
    public JSONArray regions(boolean isReload) {
        JSONArray areas = RedisUtils.getCacheObject(HikVersionConstant.CACHE_AREA + hikVersionInfo.getApiPrefix());
        if (areas == null || isReload) {
            iniConfig();
            Map<String, String> path = getPath(HikVersionConstant.REGIONS);
            JSONObject jsonBody = new JSONObject();
            jsonBody.put("pageNo", 1);
            jsonBody.put("pageSize", hikVersionInfo.getPageSize());
            String body = jsonBody.toJSONString();
            JSONObject responseResult = call(path, body);
            if (responseResult != null && "0".equals(responseResult.getString("code"))) {
                areas = responseResult.getJSONObject("data").getJSONArray("list");
                RedisUtils.setCacheObject(HikVersionConstant.CACHE_AREA + hikVersionInfo.getApiPrefix(), areas);
            }
        }
        return areas;
    }

    @Override
    public JSONArray syncAllResource(boolean isReload) {
        JSONArray cameras = RedisUtils.getCacheObject(HikVersionConstant.CACHE_CAMERA_TREE + hikVersionInfo.getApiPrefix());
        if (cameras == null || isReload) {
            iniConfig();
            Map<String, String> path = getPath(HikVersionConstant.CAMERAS_TREE);
            JSONObject jsonBody = new JSONObject();
            jsonBody.put("pageNo", 1);
            jsonBody.put("pageSize", hikVersionInfo.getPageSize());
            String body = jsonBody.toJSONString();
            JSONObject responseResult = call(path, body);
            if (responseResult != null && "0".equals(responseResult.getString("code"))) {
                cameras = responseResult.getJSONObject("data").getJSONArray("list");
                RedisUtils.setCacheObject(HikVersionConstant.CACHE_CAMERA_TREE + hikVersionInfo.getApiPrefix(), cameras);
            }
        }
        return cameras;
    }

    @Override
    public CameraTree treeList() {
        JSONArray jsonArray = RedisUtils.getCacheObject(HikVersionConstant.CACHE_CAMERA_TREE+hikVersionInfo.getApiPrefix());
        List<JSONObject> javaList = jsonArray.toJavaList(JSONObject.class);
        Map<String, List<JSONObject>> regionPathMap = javaList.stream().collect(Collectors.groupingBy(item -> item.getString("regionPathName")));
        Set<String> regionPaths = regionPathMap.keySet();
        CameraTree root = new CameraTree("top", ""); // 根节点，可能为空或者代表某个顶级域
        for (String path : regionPaths) {
            String[] parts = path.split("/");
            CameraTree current = root;
            for (String part : parts) {
                // 查找当前节点的子节点中是否存在对应名字的节点
                CameraTree matchingChild = null;
                for (CameraTree child : current.getChildren()) {
                    if (child.getName().equals(part)) {
                        matchingChild = child;
                        break;
                    }
                }
                // 如果不存在，则创建新节点
                if (matchingChild == null) {
                    matchingChild = new CameraTree(part, StringUtils.isNotBlank(current.getRegionPathName()) ? current.getRegionPathName() + "/" + part : part);
                    if (regionPathMap.containsKey(matchingChild.getRegionPathName())) {
                        matchingChild.addChild(regionPathMap.get(matchingChild.getRegionPathName()).stream()
                                .map(u -> new CameraTree(u.getString("name"), u.getString("indexCode"), u.getString("regionPathName"))).collect(Collectors.toList()));
                    }
                    current.addChild(matchingChild);
                }
                // 移动到下一层级
                current = matchingChild;
            }
        }
        return root.getChildren().get(0);
    }

    @Override
    public List<VideoInfo> getStreamUrls(List<String> codes) {
        List<VideoInfo> videoInfos = new ArrayList<>();
        JSONArray videos = syncAllResource(false);
        List<JSONObject> videoList = videos.toJavaList(JSONObject.class);
        codes.forEach(code -> {
            VideoInfo videoInfo = new VideoInfo();
            JSONObject indexCode = videoList.stream().filter(item -> item.getString("indexCode").equals(code)).findFirst().orElse(null);
            videoInfo.setCameraIndexCode(code);
            if (indexCode != null) {
                videoInfo.setCameraName(indexCode.getString("name"));
                videoInfo.setCameraUrl(getStreamUrl(new CameraStream(code, 1, "hls", null, "transcode=1&videotype=h264", null)));
            }
            videoInfos.add(videoInfo);
        });
        return videoInfos;
    }

    /**
     * 调用接口
     * post请求application/json类型参数
     */
    private JSONObject call(Map<String, String> path, String body) {
        try {
            String responseJson = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, HikVersionConstant.CONTENT_TYPE, null);
            return JSONObject.parseObject(responseJson);
        } catch (Exception e) {
            //log.error("调用接口", e);
        }
        return null;
    }


    private Map<String, String> getPath(String url) {
        Map<String, String> path = new HashMap<String, String>(2) {
            {
                //根据现场环境部署确认是http还是https
                put(hikVersionInfo.getApiPath() + "://", url);
            }
        };
        return path;
    }

    private void iniConfig() {
        // 平台的ip端口
        ArtemisConfig.host = hikVersionInfo.getApiGateway();
        // 密钥appkey
        ArtemisConfig.appKey = hikVersionInfo.getApikey();
        // 密钥appSecret
        ArtemisConfig.appSecret = hikVersionInfo.getApiSecret();
    }

}


